#include <stdio.h>
#include <string.h>

#include "cpu_card.h"

static s32 cpu_card_verify_pin(reader_op * reader)
{
	reader_data send, recv;

	if (!reader) {
		printf("cpu_card_verify_pin: para error!!!\n");
		return RET_ERR;
	}
	
	send.data = reader->deal_in_data.pin;
	recv.data = reader->recv_data;
	
	/* 校验PIN值 */
	send.type	  = READER_CONTACTLESS_CPU;
	send.cla      = 0x00;
	send.cmd.ins  = APDU_VERIFY_PIN;
	send.pa1.p1   = 0x00;
	send.pa2.p2   = 0x00;
	send.len.lc   = 3; 
	send.le	      = 0;   // 指定读取长度
	
	reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("cpu_card_verify_pin: verify pin failed!!! errno:[%02X%02X]\n", \
			recv.sw1, recv.sw2);
		return (recv.sw1 << 8 | recv.sw2);
	}
	
	return RET_OK;
}


static s32 cpu_card_deal_flow(reader_op *reader)
{
	reader_data send, recv;
	u8 key, crypt;
	u8 challenge[4];
	u8 mac[4];
	s32 ret;

	if (!reader) {
		printf("cpu_card_load_flaw para error!!!\n");
	}
	
	send.data = reader->send_data;
	recv.data = reader->recv_data;

	/* 初始化消费交易 */
	send.type	  = READER_CONTACTLESS_CPU;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_INITIALIZE_FOR_PURCHASE;
	send.pa1.p1   = 0x01; // 消费
	send.pa2.p2   = (reader->deal_in_data.deal_type == 0x01)?EP:ED; // EP（电子钱包）ED（电子存折）
	send.len.lc   = 11; 
	send.le	      = 15;   // 指定读取长度
	send.data[0]  = 0x01; // 密钥索引号
	send.data[1]  = reader->deal_in_data.deal_val[3]; // 高位在前
	send.data[2]  = reader->deal_in_data.deal_val[2];
	send.data[3]  = reader->deal_in_data.deal_val[1];
	send.data[4]  = reader->deal_in_data.deal_val[0];
	send.data[5]  = reader->psam_out_data.terminal[0]; 
	send.data[6]  = reader->psam_out_data.terminal[1]; 
	send.data[7]  = reader->psam_out_data.terminal[2]; 
	send.data[8]  = reader->psam_out_data.terminal[3]; 
	send.data[9]  = reader->psam_out_data.terminal[4]; 
	send.data[10] = reader->psam_out_data.terminal[5]; 

	ret = reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("cpu card apdu init deal failed!!! errno:[%02X%02X]\n", \
			recv.sw1, recv.sw2);
		return (recv.sw1 << 8 | recv.sw2);
	}
		
	// 返回报文数据
	
	reader->deal_out_data.deal_cnt[0] = recv.data[4];  // 交易序号
	reader->deal_out_data.deal_cnt[1] = recv.data[5];  // 交易序号
	key                               = recv.data[9];  // 密钥版本号
	crypt                             = recv.data[10]; // 算法标识
	challenge[0]                      = recv.data[11]; // 4字节伪随机数
	challenge[1]                      = recv.data[12];
	challenge[2]                      = recv.data[13];
	challenge[3]                      = recv.data[14];


	send.type	  = READER_CONTACTLESS_CPU;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_INITIALIZE_FOR_PURCHASE;
	send.pa1.p1   = 0x01;
	send.pa2.p2   = reader->deal_in_data.deal_type; 
	send.len.lc   = 11; 
	send.le	      = 15;   // 指定读取长度
	send.data[0]  = 0x01; // 密钥索引号
	send.data[1]  = reader->deal_in_data.deal_val[3];
	send.data[2]  = reader->deal_in_data.deal_val[2];
	send.data[3]  = reader->deal_in_data.deal_val[1];
	send.data[4]  = reader->deal_in_data.deal_val[0];
	send.data[5]  = reader->psam_out_data.terminal[0]; 
	send.data[6]  = reader->psam_out_data.terminal[1]; 
	send.data[7]  = reader->psam_out_data.terminal[2]; 
	send.data[8]  = reader->psam_out_data.terminal[3]; 
	send.data[9]  = reader->psam_out_data.terminal[4]; 
	send.data[10] = reader->psam_out_data.terminal[5]; 

	/* 获取MAC1 */
	send.type	  = READER_CONTACT_SAM1;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_INIT_SAM_FOR_PURCHASE;
	send.pa1.p1   = 0x00;         // 0:标准MAC1命令，1:扩展MAC1命令
	send.pa2.p2   = 0x00; 
	send.len.lc   = 28; 
	send.le	      = 0x00;         // 指定读取长度
	send.data[0]  = challenge[0]; // 密钥索引号
	send.data[1]  = challenge[1];
	send.data[2]  = challenge[2];
	send.data[3]  = challenge[3];
	send.data[4]  = reader->deal_out_data.deal_cnt[0];
	send.data[5]  = reader->deal_out_data.deal_cnt[1]; 
	send.data[6]  = reader->deal_in_data.deal_val[3]; 
	send.data[7]  = reader->deal_in_data.deal_val[2]; 
	send.data[8]  = reader->deal_in_data.deal_val[1]; 
	send.data[9]  = reader->deal_in_data.deal_val[0]; 
	send.data[10] = (reader->deal_in_data.deal_type == 0x01)?0x06:0x05; // 0x06=钱包消费，0x05=存折消费
	send.data[11]  = reader->deal_in_data.deal_time[0];
	send.data[12]  = reader->deal_in_data.deal_time[1];
	send.data[13]  = reader->deal_in_data.deal_time[2];
	send.data[14]  = reader->deal_in_data.deal_time[3];
	send.data[15]  = reader->deal_in_data.deal_time[4]; 
	send.data[16]  = reader->deal_in_data.deal_time[5]; 
	send.data[17]  = reader->deal_in_data.deal_time[6]; 
	send.data[18]  = key; 
	send.data[19]  = crypt; 
	send.data[20]  = reader->deal_in_data.card_id[0]; 
	send.data[21]  = reader->deal_in_data.card_id[1]; 
	send.data[22]  = reader->deal_in_data.card_id[2]; 
	send.data[23]  = reader->deal_in_data.card_id[3]; 
	send.data[24]  = reader->deal_in_data.card_id[4]; 
	send.data[25]  = reader->deal_in_data.card_id[5]; 
	send.data[26]  = reader->deal_in_data.card_id[6]; 
	send.data[27]  = reader->deal_in_data.card_id[7]; 

	
	ret = reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 == 0x61)) {		
		psam_apdu_get_response(&send, &recv);
		ret = reader_communication(reader->fd, &send, &recv);
	}

	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("pasm get mac1 failed!!!\n");
		return (recv.sw1 << 8 | recv.sw2);
	}

	// 终端流水号 和 MAC1
	reader->psam_out_data.deal_index[0] = recv.data[0];
	reader->psam_out_data.deal_index[1] = recv.data[1];
	reader->psam_out_data.deal_index[2] = recv.data[2];
	reader->psam_out_data.deal_index[3] = recv.data[3];
	mac[0] = recv.data[4];
	mac[1] = recv.data[5];
	mac[2] = recv.data[6];
	mac[3] = recv.data[7];
	
	/* 消费 */
	send.type	  = READER_CONTACTLESS_CPU;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_DEBIT_FOR_PURCHASE;
	send.pa1.p1   = 0x01; 
	send.pa2.p2   = 0x00; 
	send.len.lc   = 15; 
	send.le	      = 0x08;   // 指定读取长度
	send.data[0]  = reader->psam_out_data.deal_index[0]; 
	send.data[1]  = reader->psam_out_data.deal_index[1];
	send.data[2]  = reader->psam_out_data.deal_index[2];
	send.data[3]  = reader->psam_out_data.deal_index[3];
	send.data[4]  = reader->deal_in_data.deal_time[0];
	send.data[5]  = reader->deal_in_data.deal_time[1]; 
	send.data[6]  = reader->deal_in_data.deal_time[2]; 
	send.data[7]  = reader->deal_in_data.deal_time[3]; 
	send.data[8]  = reader->deal_in_data.deal_time[4]; 
	send.data[9]  = reader->deal_in_data.deal_time[5]; 
	send.data[10] = reader->deal_in_data.deal_time[6]; 
	send.data[11]  = mac[0];
	send.data[12]  = mac[1];
	send.data[13]  = mac[2];
	send.data[14]  = mac[3];

	ret = reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("cpu card deal failed!!! errno:[%02X%02X]\n", \
			recv.sw1, recv.sw2);
		return (recv.sw1 << 8 | recv.sw2);
	}

	// 返回报文 tac 和 mac2
	reader->deal_out_data.deal_tac[0] = recv.data[0];
	reader->deal_out_data.deal_tac[1] = recv.data[1];
	reader->deal_out_data.deal_tac[2] = recv.data[2];
	reader->deal_out_data.deal_tac[3] = recv.data[3];
	mac[0] = recv.data[4];
	mac[1] = recv.data[5];
	mac[2] = recv.data[6];
	mac[3] = recv.data[7];

	/* MAC2校验 */
	send.type	  = READER_CONTACT_SAM1;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_CREDIT_SAM_FOR_PURCHASE;
	send.pa1.p1   = 0x00; 
	send.pa2.p2   = 0x00; 
	send.len.lc   = 0x04; 
	send.le	      = 0x00;   // 指定读取长度
	send.data[0]  = mac[0]; 
	send.data[1]  = mac[1];
	send.data[2]  = mac[2];
	send.data[3]  = mac[3];

	ret = reader_communication(reader->fd, &send, &recv); 
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("cpu card check Mac2 failed!!! errno:[%02X%02X]\n", \
			recv.sw1, recv.sw2);
		return (recv.sw1 << 8 | recv.sw2);
	}	

	if (DEBUG_APP_WALL > __DEBUG_APP_O0__) {
		printf("DEBGU_info: cpu card deal done\n");
	}

	return (0x9000);
}



static s32 cpu_card_load_flow(reader_op *reader)
{
	reader_data send, recv;
	u8 key, crypt;
	u8 challenge[4];
	u8 mac[4];
	s32 ret;

	if (!reader) {
		printf("cpu_card_load_flaw para error!!!\n");
	}
	
	send.data = reader->send_data;
	recv.data = reader->recv_data;

	ret = cpu_card_verify_pin(reader);
	if (ret) {
		return RET_ERR;
	}
	
	/* 初始化圈存命令 */
	send.type	  = READER_CONTACTLESS_CPU;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_INITIALIZE_FOR_PURCHASE;
	send.pa1.p1   = 0x00; // 圈存
	send.pa2.p2   = (reader->deal_in_data.deal_type == 0x01)?EP:ED; // EP（电子钱包）ED（电子存折）
	send.len.lc   = 11; 
	send.le	      = 16;   // 指定读取长度
	send.data[0]  = 0x01; // 密钥索引号
	send.data[1]  = reader->deal_in_data.deal_val[3]; // 高位在前
	send.data[2]  = reader->deal_in_data.deal_val[2];
	send.data[3]  = reader->deal_in_data.deal_val[1];
	send.data[4]  = reader->deal_in_data.deal_val[0];
	send.data[5]  = reader->psam_out_data.terminal[0]; 
	send.data[6]  = reader->psam_out_data.terminal[1]; 
	send.data[7]  = reader->psam_out_data.terminal[2]; 
	send.data[8]  = reader->psam_out_data.terminal[3]; 
	send.data[9]  = reader->psam_out_data.terminal[4]; 
	send.data[10] = reader->psam_out_data.terminal[5]; 

	ret = reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("cpu card apdu init load failed!!! errno:[%02X%02X]\n", \
			recv.sw1, recv.sw2);
		return (recv.sw1 << 8 | recv.sw2);
	}
		
	// 返回报文数据
	reader->deal_in_data.money_val[0] = recv.data[0];
	reader->deal_in_data.money_val[1] = recv.data[1];
	reader->deal_in_data.money_val[2] = recv.data[2];
	reader->deal_in_data.money_val[3] = recv.data[3];
	reader->deal_out_data.deal_cnt[0] = recv.data[4];   // 交易序号
	reader->deal_out_data.deal_cnt[1] = recv.data[5];   // 交易序号
	key                               = recv.data[6];	// 密钥版本号
	crypt                             = recv.data[7]; 	// 算法标识
	challenge[0]                      = recv.data[8]; 	// 4字节伪随机数
	challenge[1]                      = recv.data[9];
	challenge[2]                      = recv.data[10];
	challenge[3]                      = recv.data[11];
	mac[0]							  = recv.data[12];	
	mac[1]							  = recv.data[13];	
	mac[2]							  = recv.data[14];	
	mac[3]							  = recv.data[15];	

	ret = reader_get_factor(reader);
	if (ret) {
		return RET_ERR;
	}

	// 获取圈存过程密钥 
	memset(recv.data, 0, READER_BUF_SIZ);
	recv.data[0] = challenge[0];
	recv.data[1] = challenge[1];
	recv.data[2] = challenge[2];
	recv.data[3] = challenge[3];
	recv.data[4] = reader->deal_out_data.deal_cnt[0];
	recv.data[5] = reader->deal_out_data.deal_cnt[1];
	recv.data[6] = 0x80;
	recv.data[7] = 0x00;
	reader->op_type = READER_LOAD_OP_FLAG;
	ret = psam_card_get_key(reader, CTCC_YJD_KEY_FLAG, CTCC_YJD_KEY_ID_LOAD);
	if (ret) {
		printf("cpu_card_load_flow: get key failed!!!\n");
		return RET_ERR;
	}

	/* 获取MAC1 */
	memset(send.data, 0, READER_BUF_SIZ);
	send.type	  = READER_CONTACT_SAM1;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_INIT_SAM_FOR_PURCHASE;
	send.pa1.p1   = 0x00;         // 0:标准MAC1命令，1:扩展MAC1命令
	send.pa2.p2   = 0x00; 
	send.len.lc   = 28; 
	send.le	      = 0x00;         // 指定读取长度

	send.data[0]  = challenge[0]; // 余额
	send.data[1]  = challenge[1];
	send.data[2]  = challenge[2];
	send.data[3]  = challenge[3];
	send.data[4]  = reader->deal_out_data.deal_cnt[0]; // 交易金额
	send.data[5]  = reader->deal_out_data.deal_cnt[1];
	send.data[6]  = 0x80;
	send.data[7]  = 0x00;
	send.data[8]  = reader->deal_in_data.money_val[0]; // 余额
	send.data[9]  = reader->deal_in_data.money_val[1];
	send.data[10]  = reader->deal_in_data.money_val[2];
	send.data[11]  = reader->deal_in_data.money_val[3];
	send.data[12]  = reader->deal_in_data.deal_val[3]; // 交易金额
	send.data[13]  = reader->deal_in_data.deal_val[2];
	send.data[14]  = reader->deal_in_data.deal_val[1];
	send.data[15]  = reader->deal_in_data.deal_val[0];
	send.data[16]  = (reader->deal_in_data.deal_type == 0x01)?EP:ED; // EP（电子钱包）ED（电子存折）
	send.data[17]  = reader->psam_out_data.terminal[0]; 
	send.data[18]  = reader->psam_out_data.terminal[1]; 
	send.data[19]  = reader->psam_out_data.terminal[2]; 
	send.data[20]  = reader->psam_out_data.terminal[3]; 
	send.data[21]  = reader->psam_out_data.terminal[4]; 
	send.data[22] = reader->psam_out_data.terminal[5];
#if 0
	send.data[0]  = reader->deal_in_data.money_val[0]; // 余额
	send.data[1]  = reader->deal_in_data.money_val[1];
	send.data[2]  = reader->deal_in_data.money_val[2];
	send.data[3]  = reader->deal_in_data.money_val[3];
	send.data[4]  = reader->deal_in_data.deal_val[3]; // 交易金额
	send.data[5]  = reader->deal_in_data.deal_val[2];
	send.data[6]  = reader->deal_in_data.deal_val[1];
	send.data[7]  = reader->deal_in_data.deal_val[0];
	send.data[8]  = (reader->deal_in_data.deal_type == 0x01)?EP:ED; // EP（电子钱包）ED（电子存折）
	send.data[9]  = reader->psam_out_data.terminal[0]; 
	send.data[10]  = reader->psam_out_data.terminal[1]; 
	send.data[11]  = reader->psam_out_data.terminal[2]; 
	send.data[12]  = reader->psam_out_data.terminal[3]; 
	send.data[13]  = reader->psam_out_data.terminal[4]; 
	send.data[14] = reader->psam_out_data.terminal[5];
#endif

	ret = psam_card_apdu_comm(&send, 15, reader->deal_in_data.m1.key_data, SKEY_TYPE, reader->recv_data);
	if (ret) {
		return RET_ERR;
	}


	printf("new mac: %x %x %x %x\nold mac: %x %x %x %x\n", reader->recv_data[0], \
		reader->recv_data[1], reader->recv_data[2], reader->recv_data[3], \
		mac[0], mac[1], mac[2], mac[3]);

	// 验证MAC1
	if (memcmp(reader->recv_data, mac, 4)) {
		printf("cpu_card_load_flow: check mac1 error!!!\n");
		return RET_ERR;
	}

	/* 圈存 */
	send.type	  = READER_CONTACTLESS_CPU;
	send.cla      = 0x80;
	send.cmd.ins  = APDU_DEBIT_FOR_PURCHASE;
	send.pa1.p1   = 0x00; 
	send.pa2.p2   = 0x00; 
	send.len.lc   = 11; 
	send.le	      = 0x04;   // 指定读取长度

	send.data[0]  = reader->deal_in_data.deal_time[0];
	send.data[1]  = reader->deal_in_data.deal_time[1]; 
	send.data[2]  = reader->deal_in_data.deal_time[2]; 
	send.data[3]  = reader->deal_in_data.deal_time[3]; 
	send.data[4]  = reader->deal_in_data.deal_time[4]; 
	send.data[5]  = reader->deal_in_data.deal_time[5]; 
	send.data[6]  = reader->deal_in_data.deal_time[6]; 
	send.data[7]  = reader->recv_data[4];
	send.data[8]  = reader->recv_data[5];
	send.data[9]  = reader->recv_data[6];
	send.data[10]  = reader->recv_data[7];

	ret = reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("cpu card load failed!!! errno:[%02X%02X]\n", \
			recv.sw1, recv.sw2);
		return (recv.sw1 << 8 | recv.sw2);
	}

	// 返回报文 tac
	reader->deal_out_data.deal_tac[0] = recv.data[0];
	reader->deal_out_data.deal_tac[1] = recv.data[1];
	reader->deal_out_data.deal_tac[2] = recv.data[2];
	reader->deal_out_data.deal_tac[3] = recv.data[3];


	if (DEBUG_APP_WALL > __DEBUG_APP_O0__) {
		printf("DEBGU_info: cpu card load done\n");
	}

	return (0x9000);
}



static s32 cpu_card_select_file(reader_op *reader)
{
	reader_data send, recv;

	if (!reader->deal_in_data.name || !reader->deal_in_data.path) {
		printf("cpu_card_select_file pare error!!!\n");
	}

	send.data = reader->send_data;
	recv.data = reader->recv_data;

	memset(send.data, 0, READER_BUF_SIZ);
	strncpy(send.data, reader->deal_in_data.name, \
		strlen(reader->deal_in_data.name));
	/* 按文件名选择应用文件 */
	send.type    = READER_CONTACTLESS_CPU;
	send.cla     = 0x00;
	send.cmd.ins = APDU_SELECT_FILE;
	send.pa1.p1  = 0x04;
	send.pa2.p2  = 0x00;
	send.len.lc  = strlen(send.data);
	send.le      = 0;

	reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("select cpu %s file failed\n", reader->deal_in_data.name);
		return RET_ERR;
	}

	// 进入子目录
	memset(send.data, 0, READER_BUF_SIZ);
	strncpy(send.data, reader->deal_in_data.path, \
		strlen(reader->deal_in_data.path));
	send.type    = READER_CONTACTLESS_CPU;
	send.cla     = 0x00;
	send.cmd.ins = APDU_SELECT_FILE;
	send.pa1.p1  = 0x00;
	send.pa2.p2  = 0x00;
	send.len.lc  = strlen(send.data);
	send.le      = 0;

	reader_communication(reader->fd, &send, &recv);
	if ((recv.sw1 << 8 | recv.sw2) != 0x9000) {
		printf("select cpu %s file failed\n", reader->deal_in_data.path);
		return RET_ERR;
	}

	if (DEBUG_APP_WALL > __DEBUG_APP_O1__) {
		printf("DEBGU_info: cpu card select file done\n");
	}

	return RET_OK;
}



/************************************
 * func: cpu卡交易操作
 * para:
 *
 *  ret:
 *    返回指令报文
 ***********************************/
s32 cpu_card_deal(void *op)
{
	s32 ret = 0;
	reader_op *reader = (reader_op *)op;

	if (!op) {
		printf("cpu_card_deal para error!!!\n");
		return RET_ERR;
	}

	// 选择CPU文件
	ret = cpu_card_select_file(reader);
	if (ret) {
		return RET_ERR;
	}

	// 交易认证过程
	ret = cpu_card_deal_flow(reader);
	if (ret != 0x9000) {
		return RET_ERR;
	}


	return RET_OK;
}




/************************************
 * func: cpu卡圈存操作
 * para:
 *
 *  ret:
 *    返回指令报文
 ***********************************/
s32 cpu_card_load(void *op)
{
	s32 ret = 0;
	reader_op *reader = (reader_op *)op;

	if (!op) {
		printf("cpu_card_deal para error!!!\n");
		return RET_ERR;
	}

	// 选择CPU文件
	ret = cpu_card_select_file(reader);
	if (ret) {
		return RET_ERR;
	}

	// 交易认证过程
	ret = cpu_card_load_flow(reader);
	if (ret != 0x9000) {
		return RET_ERR;
	}


	return RET_OK;
}



#if 0
int cpu_card_get_detail(void *info)
{
	int ret;
	char buf[128];
	READER_CCID_T send_recv;


	printf("select CPU MF\n");
	reader_transcive(&send_recv, &send_recv);
/*
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("select CPU MF fail\n");
		return -ERR_CARD_OP;
	}
*/
	/* 按文件名选择文件 */
	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x00;
	send_recv.CMD.INS = APDU_SELECT_FILE;
#ifdef __USE_FIXED_AID__
	send_recv.PA1.P1  = 0x00;
	send_recv.LEN.Lc  = 2;
	send_recv.DATA[0] = 0xDF;
	send_recv.DATA[1] = 0x10;
#else
	send_recv.PA1.P1  = 0x04;
	send_recv.LEN.Lc  = 16;
	for(ret=0; ret<16; ret++) {
		send_recv.DATA[ret] = server_info.CardAID[ret];
	}
#endif
	printf("select CPU YJT\n");
	reader_transcive(&send_recv, &send_recv);
#if 0
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("select user card(CPU) YJT app fail\n");
		return -ERR_CARD_OP;
	}
#endif

	/* 读二进制带SFI选择文件 */
	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x00;
	send_recv.CMD.INS = APDU_READ_BINARY;
	send_recv.PA1.P1  = 0x95; /* bit7=1，bit6-bit5=0，bit4-bit0='SFI' */
	send_recv.PA2.P2  = 10; /* 指定读取偏移量（相对文件头部）*/
	send_recv.LEN.Lc  = 0; 
	send_recv.Le      = 18; /* 指定读取长度 */
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("read CPU SFI-21 fail\n");
		return -ERR_CARD_OP;
	}
	info->asn[0] = send_recv.DATA[0];
	info->asn[1] = send_recv.DATA[1];
	info->asn[2] = send_recv.DATA[2];
	info->asn[3] = send_recv.DATA[3];
	info->asn[4] = send_recv.DATA[4];
	info->asn[5] = send_recv.DATA[5];
	info->asn[6] = send_recv.DATA[6];
	info->asn[7] = send_recv.DATA[7];
	info->asn[8] = send_recv.DATA[8];
	info->asn[9] = send_recv.DATA[9];
	info->app_begin = (send_recv.DATA[13]<<0)
		| (send_recv.DATA[12]<<8)
		| (send_recv.DATA[11]<<16)
		| (send_recv.DATA[10]<<24);
	info->card_indate = (send_recv.DATA[17]<<0)
		| (send_recv.DATA[16]<<8)
		| (send_recv.DATA[15]<<16)
		| (send_recv.DATA[14]<<24);

	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x00;
	send_recv.CMD.INS = APDU_READ_BINARY;
	send_recv.PA1.P1  = 0x96; /* bit7=1，bit6-bit5=0，bit4-bit0='SFI' */
	send_recv.PA2.P2  = 2; /* 指定读取偏移量（相对文件头部）*/
	send_recv.LEN.Lc  = 0; 
	send_recv.Le      = 20; /* 指定读取长度 */
	send_recv.DATA    = info->name;
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("read CPU SFI-22 fail\n");
		return -ERR_CARD_OP;
	}

	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x00;
	send_recv.CMD.INS = APDU_READ_BINARY;
	send_recv.PA1.P1  = 0x96; /* bit7=1，bit6-bit5=0，bit4-bit0='SFI' */
	send_recv.PA2.P2  = 88; /* 指定读取偏移量（相对文件头部）*/
	send_recv.LEN.Lc  = 0; 
	send_recv.Le      = 13; /* 指定读取长度 */
	send_recv.DATA    = buf;
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("read CPU SFI-22 fail\n");
		return -ERR_CARD_OP;
	}
#define __CST_CARD_TYPE__ 0
/* 郑州新开普、江苏鸿程 */
#define __OTHER_CARD_TYPE__ 1
/* 广州亿迅和浙江鸿程 */
#define __YIXUN_CARD_TYPE__ 0

#if __CST_CARD_TYPE__
#warning "use cst card type define[88]" 
	info->card_class = send_recv.DATA[88-88];
#elif __OTHER_CARD_TYPE__
#warning "use other card type define[98]" 
	info->card_class = send_recv.DATA[98-88];
#elif __YIXUN_CARD_TYPE__
#warning "use yixun card type define[100]" 
	info->card_class = send_recv.DATA[100-88]; /* 广州亿迅 */
#else
#error "please define a card type byte" 
#endif
#undef __CST_CARD_TYPE__
#undef __OTHER_CARD_TYPE__
#undef __YIXUN_CARD_TYPE__
	info->card_func = send_recv.DATA[97-88];

	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x00;
	send_recv.CMD.INS = APDU_READ_BINARY;
	send_recv.PA1.P1  = 0x99; /* bit7=1，bit6-bit5=0，bit4-bit0='SFI' */
	send_recv.PA2.P2  = 0; /* 指定读取偏移量（相对文件头部）*/
	send_recv.LEN.Lc  = 0; 
	send_recv.Le      = 54; /* 指定读取长度 */
	send_recv.DATA    = info->card_private_info;
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("read CPU SFI-25 fail\n");
		return -ERR_CARD_OP;
	}

	info->card_status = info->card_private_info[0];
	info->terminal_no[0] = info->card_private_info[1];
	info->terminal_no[1] = info->card_private_info[2];
	info->terminal_no[2] = info->card_private_info[3];
	info->terminal_no[3] = info->card_private_info[4];
	info->terminal_no[4] = info->card_private_info[5];
	info->terminal_no[5] = info->card_private_info[6];
	info->consume_indate = (info->card_private_info[7]<<24)
		| (info->card_private_info[8]<<16)
		| (info->card_private_info[9]<<8)
		| (info->card_private_info[10]<<0);
	info->limit_v_per_meal = (info->card_private_info[15]<<8)
		| (info->card_private_info[16]<<0);
	info->limit_v_per_deal = (info->card_private_info[17]<<8)
		| (info->card_private_info[18]<<0);
	info->limit_v_per_day = (info->card_private_info[19]<<8)
		| (info->card_private_info[20]<<0);
	info->meal_sum = (info->card_private_info[32]<<24)
		| (info->card_private_info[33]<<16)
		| (info->card_private_info[34]<<8)
		| (info->card_private_info[35]<<0);
	info->day_sum = (info->card_private_info[36]<<24)
		| (info->card_private_info[37]<<16)
		| (info->card_private_info[38]<<8)
		| (info->card_private_info[39]<<0);
	info->last_use_date = (info->card_private_info[40]<<8)
		| (info->card_private_info[41]<<0);
	info->last_meal_type = info->card_private_info[42];
	info->last_meal_cnt = info->card_private_info[43];
	info->last_day_cnt = info->card_private_info[44];
	info->ed_zero_date = (info->card_private_info[45]<<24)
		| (info->card_private_info[46]<<16)
		| (info->card_private_info[47]<<8)
		| (info->card_private_info[48]<<0);
	info->passwd_mac = (info->card_private_info[21]<<24)
		| (info->card_private_info[22]<<16)
		| (info->card_private_info[23]<<8)
		| (info->card_private_info[24]<<0);
	info->passwd_ver = (info->card_private_info[25]<<24)
		| (info->card_private_info[26]<<16)
		| (info->card_private_info[27]<<8)
		| (info->card_private_info[28]<<0);

	/* 读取电子钱包电子存折的余额 */
	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x80;
	send_recv.CMD.INS = APDU_GET_BALANCE;
	send_recv.PA1.P1  = 0x00;
	send_recv.PA2.P2  = 0x02; /* 0x01=ED（电子存折）, 0x02=EP（电子钱包）*/
	send_recv.LEN.Lc  = 0; 
	send_recv.Le      = 4; /* 指定读取长度 */
	send_recv.DATA    = buf;
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("get ep balance fail\n");
		return -ERR_CARD_OP;
	}
	info->ep_balance = (send_recv.DATA[0]<<24)
			| (send_recv.DATA[1]<<16)
			| (send_recv.DATA[2]<<8)
			| (send_recv.DATA[3]<<0);
	/* 操作电子存折前验证PIN */
	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x00;
	send_recv.CMD.INS = APDU_VERIFY_PIN;
	send_recv.PA1.P1  = 0x00;
	send_recv.PA2.P2  = 0x00;
	send_recv.LEN.Lc  = 3; 
	send_recv.Le      = 0; /* 指定读取长度 */
	send_recv.DATA[0] = 0;
	send_recv.DATA[1] = 0;
	send_recv.DATA[2] = 0;
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("get verify pin fail\n");
		return -ERR_CARD_OP;
	}
	send_recv.type    = READER_CONTACTLESS_CPU;
	send_recv.CLA     = 0x80;
	send_recv.CMD.INS = APDU_GET_BALANCE;
	send_recv.PA1.P1  = 0x00;
	send_recv.PA2.P2  = 0x01; /* 0x01=ED（电子存折）, 0x02=EP（电子钱包）*/
	send_recv.LEN.Lc  = 0; 
	send_recv.Le      = 4; /* 指定读取长度 */
	reader_transcive(&send_recv, &send_recv);
	if((send_recv.SW1!=0x90) || (send_recv.SW2!=0x00)) {
		printf("get ed balance fail\n");
		return -ERR_CARD_OP;
	}
	info->ed_balance = (send_recv.DATA[0]<<24)
			| (send_recv.DATA[1]<<16)
			| (send_recv.DATA[2]<<8)
			| (send_recv.DATA[3]<<0);

	info->card_type = 0x02;
	info->card_id = *(unsigned int *)card_id;

	printf("cpu card slect\n");
	return 0;
}
#endif



